library BindUnitMovement /* v1.1


    */requires /*

    */UnitDex             /*  http://www.hiveworkshop.com/threads/system-unitdex-unit-indexer.248209
    */optional GroupUtils /*  http://www.wc3c.net/showthread.php?t=104464

    A simple library which provides functions for binding a unit to a specific
    location for a certain duration. Binded units can still attack, perform
    orders, cast spells, and display their walk animation but they are not able
    to move outside their bind location.

*///! novjass

    [Author] : AGD

        |=====|
        | API |
        |=====|

            function BindUnitMovement takes unit u, real duration returns nothing/*
                - Prevents a unit from moving out of its current location
                - Bind duration does not stack but overrides the previous one

          */function UnbindUnitMovement takes unit u returns nothing/*
                - Unbinds a unit, allowing it to move outside its current location

          */function IsUnitMovementBinded takes unit u returns boolean/*
                - Checks is the unit's movement is binded

          */function SetBindedUnitX takes unit u, real x returns nothing/*
          */function SetBindedUnitY takes unit u, real y returns nothing/*
                - Sets new coordinates for a unit's bind location
                - Can only be applied to currently binded units

          */function GetBindedUnitX takes unit u returns real/*
          */function GetBindedUnitY takes unit u returns real/*
                - Gets the coordinates of the unit's bind location

*///! endnovjass

    /*==========================================================================*/

    private module Init
        private static method onInit takes nothing returns nothing
            local code c = function thistype.onLeave
            call OnUnitDeindex(c)
        endmethod
    endmodule

    private struct Binder extends array

        real uX
        real uY
        real duration
        static unit tempUnit
        static timer timer = CreateTimer()
        static group forSwap
        static group bindedGroup = CreateGroup()

        static if not LIBRARY_GroupUtils then
            static group ENUM_GROUP = CreateGroup()
        endif

        static method periodic takes nothing returns nothing
            local thistype this
            loop
                set tempUnit = FirstOfGroup(bindedGroup)
                exitwhen tempUnit == null
                call GroupRemoveUnit(bindedGroup, tempUnit)
                set this = GetUnitId(tempUnit)
                if .duration > 0 then
                    set .duration = .duration - 0.031250000
                    call SetUnitX(tempUnit, .uX)
                    call SetUnitY(tempUnit, .uY)
                    call GroupAddUnit(ENUM_GROUP, tempUnit)
                endif
            endloop
            set forSwap = bindedGroup
            set bindedGroup = ENUM_GROUP
            set ENUM_GROUP = forSwap
            if FirstOfGroup(bindedGroup) == null then
                call PauseTimer(timer)
            endif
        endmethod

        static method onLeave takes nothing returns nothing
            call GroupRemoveUnit(bindedGroup, GetIndexedUnit())
        endmethod

        implement Init

    endstruct

    /*==========================================================================*/

    function BindUnitMovement takes unit u, real dur returns nothing
        local Binder this = GetUnitId(u)
        set this.duration = dur
        if not IsUnitInGroup(u, Binder.bindedGroup) then
            set this.uX = GetUnitX(u)
            set this.uY = GetUnitY(u)
            if FirstOfGroup(Binder.bindedGroup) == null then
                call TimerStart(Binder.timer, 0.031250000, true, function Binder.periodic)
            endif
            call GroupAddUnit(Binder.bindedGroup, u)
        endif
    endfunction

    function UnbindUnitMovement takes unit u returns nothing
        call GroupRemoveUnit(Binder.bindedGroup, u)
    endfunction

    function IsUnitMovementBinded takes unit u returns boolean
        return IsUnitInGroup(u, Binder.bindedGroup)
    endfunction

    function SetBindedUnitX takes unit u, real x returns nothing
        set Binder(GetUnitId(u)).uX = x
        call SetUnitX(u, x)
    endfunction

    function SetBindedUnitY takes unit u, real y returns nothing
        set Binder(GetUnitId(u)).uY = y
        call SetUnitX(u, y)
    endfunction

    function GetBindedUnitX takes unit u returns real
        if IsUnitMovementBinded(u) then
            return Binder(GetUnitId(u)).uX
        endif
        return 0.00
    endfunction

    function GetBindedUnitY takes unit u returns real
        if IsUnitMovementBinded(u) then
            return Binder(GetUnitId(u)).uY
        endif
        return 0.00
    endfunction


endlibrary